package cn.tedu.csmall.passport.filter;

import cn.tedu.csmall.passport.security.LoginPrincipal;
import cn.tedu.csmall.passport.web.JsonResult;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component
public class JwtAuthorizationFilter extends OncePerRequestFilter {
    @Value("${csmall.jwt.secret-key}")
    private String secretKey;

    public JwtAuthorizationFilter() {
        log.debug("创建过滤器：JwtAuthorizationFilter");
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        log.debug("执行JwtAuthorizationFilter过滤器");
        //清除Security上下文的数据
        SecurityContextHolder.clearContext();

        //从请求头中获取JWT
        String jwt=request.getHeader("Authorization");
        log.debug("从请求中获取JWT：{}",jwt);
        //判断JWT是否存在
        if(!StringUtils.hasText(jwt)||jwt.length()<80){
            log.debug("获取的JWT是无效的,直接放行，交给后续组件继续放行");
            //让过滤器继续执行，相当于：放行
            filterChain.doFilter(request,response);
            //返回终止当前方法
            return;
        }
        //尝试解析JWT
        Claims claims=null;
        try{
            claims=Jwts.parser().setSigningKey(secretKey)
                    .parseClaimsJws(jwt).getBody();
        }catch (MalformedJwtException e) {
            log.warn("解析JWT失败：{}：{}", e.getClass().getName(), e.getMessage());
            JsonResult<Void>jsonResult=JsonResult.fail(
                    ServiceCode.ERR_JWT_PARSE, "无法获取到有效的登录信息，请重新登录！"
            );
            String jsonResultString = JSON.toJSONString(jsonResult);
            PrintWriter writer=response.getWriter();
            writer.println(jsonResultString);
            writer.close();
            return;
        }catch (SignatureException e){
            log.warn("解析JWT失败：{}：{}", e.getClass().getName(), e.getMessage());
            JsonResult<Void>jsonResult=JsonResult.fail(
                    ServiceCode.ERR_JWT_PARSE, "无法获取到有效的登录信息，请重新登录！"
            );
            String jsonResultString = JSON.toJSONString(jsonResult);
            PrintWriter writer=response.getWriter();
            writer.println(jsonResultString);
            writer.close();
            return;

        } catch (ExpiredJwtException e) {
            log.warn("解析JWT失败：{}：{}", e.getClass().getName(), e.getMessage());
            JsonResult<Void>jsonResult=JsonResult.fail(
                    ServiceCode.ERR_JWT_EXPIRE, "登录信息已过期，请重新登录！"
            );
            String jsonResultString = JSON.toJSONString(jsonResult);
            PrintWriter writer=response.getWriter();
            writer.println(jsonResultString);
            writer.close();
            return;
        }catch (Throwable e) {
            log.warn("解析JWT失败：{}：{}", e.getClass().getName(), e.getMessage());
            JsonResult<Void>jsonResult=JsonResult.fail(
                    ServiceCode.ERR_JWT_PARSE, "无法获取到有效的登录信息，请重新登录！"
            );
            String jsonResultString = JSON.toJSONString(jsonResult);
            PrintWriter writer=response.getWriter();
            writer.println(jsonResultString);
            writer.close();
            return;
        }

        //从JWT的解析结果中获取数据
        Long id=claims.get("id",Long.class);
        String username =claims.get("username",String.class);
        String authorityListString=claims.get("authorities",String.class);
        log.debug("从JWT中解析得到参数id={}",id);
        log.debug("从JWT中解析得到参数username={}",username);
        log.debug("从JWT中解析得到参数authorities={}",authorityListString);

        //准备Authentication对象，后续会将此对象封装到Security的上下文中
        LoginPrincipal loginPrincipal=new LoginPrincipal();
        loginPrincipal.setId(id);
        loginPrincipal.setUsername(username);
        List<SimpleGrantedAuthority>authorities = JSON.parseArray(
                authorityListString.toString(),SimpleGrantedAuthority.class
        );
        authorities.add(new SimpleGrantedAuthority("临时使用的权限"));
        Authentication authentication=new UsernamePasswordAuthenticationToken(
               loginPrincipal,null,authorities);
        //将用户信息封装到Security的上下文中
        SecurityContext securityContext= SecurityContextHolder.getContext();
        securityContext.setAuthentication(authentication);
        //让过滤器继续执行，相当于：放行
        filterChain.doFilter(request,response);
    }
}
